﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.XLANGs.BaseTypes;
using System.Diagnostics;
using Software41.Tracking.Tracing;

namespace Software41.Tracking.BAM
{
    [Serializable]
    public class StepInfo : InfoBase
    {
        //internal const string STEPINFO_ACTIVITY = "StepInfo";
        //internal const string STEPINFO_ACTIVITY_NAME = "Name";
        //internal const string STEPINFO_ACTIVITY_BEGIN = "Begin";
        //internal const string STEPINFO_ACTIVITY_END = "End";
        //internal const string STEPINFO_ACTIVITY_SUCCESS = "Success";
        //internal const string STEPINFO_ACTIVITY_DATA = "StepInfoData";
        //internal const string STEPINFO_ACTIVITY_DATA_BEGIN_DATA = "BeginData";
        //internal const string STEPINFO_ACTIVITY_DATA_END_DATA = "EndData";

        public string StepInfoId { get { return this.InfoId; } }
        public string ParentProcessInfoId { get { return this.ParentInfoId; } }
        private List<ActionInfo> DependentActionInfos { get; set; }
       


        public StepInfo(string name, string stepInfoId, string parentProcessInfoId, IEventStream eventStream)
        {
            this.Name = name;
            this.InfoId = stepInfoId;
            this.ParentInfoId = parentProcessInfoId;
            this.EventStream = eventStream;
            this.DependentActionInfos = new List<ActionInfo>();
            this.CurrentActivityType = ActivityType.StepInfo;
            this.ParentActivityType = ActivityType.ProcessTraceInfo;
        }

        public StepInfo(string name, string stepInfoId, string parentProcessInfoId)
            : this(name, stepInfoId, parentProcessInfoId, new Adapters.OrchestrationEventStreamAdapter())
        {
        }

        public StepInfo(string name, string parentProcessInfoId, IEventStream eventStream)
            : this(name, null, parentProcessInfoId, eventStream)
        {
        }

        public StepInfo(string name, string parentProcessInfoId)
            : this(name, null, parentProcessInfoId)
        {
        }

        /// <summary>
        /// This method should ONLY be used when you want to Update/End an already started StepInfo
        /// </summary>
        /// <param name="stepInfoId"></param>
        /// <param name="eventStream"></param>
        public StepInfo(string stepInfoId, IEventStream eventStream)
            : this(null, stepInfoId, null, eventStream)
        {
            this.State = ActivityStateType.Started;
        }

        /// <summary>
        /// This method should ONLY be used when you want to Update/End an already started StepInfo
        /// </summary>
        /// <param name="stepInfoId"></param>
        public StepInfo(string stepInfoId)
            : this(null, stepInfoId, null as string)
        {
            this.State = ActivityStateType.Started;
        }


        #region End Methods
        

        internal override void EndInternal(bool success, string messageDataName, string messageData)
        {
            this.EndDependentActions();
            base.EndInternal(success, messageDataName, messageData);
        }

        
        #endregion

        #region ActionInfo Management Methods

        public ActionInfo AddActionInfo(string ActionInfoName)
        {
            ActionInfo actionInfo = new ActionInfo(ActionInfoName, this.StepInfoId, this.EventStream);

            this.DependentActionInfos.Add(actionInfo);

            return actionInfo;

        }

        private void EndDependentActions()
        {
            this.DependentActionInfos.ForEach(a =>
            {
                if (a.State == ActivityStateType.Started)
                {
                    //something happened that we did not call end on this 
                    a.End(false);
                }

            });
        }
        #endregion

        #region ExceptionInfo Mgmt

        public override void AddException(Exception ex)
        {
            base.AddException(ex);
            this.ExceptionDetail.Begin(this);
        }

        #endregion

        #region AddDetail Mgmt
        public override LogDetail AddLogDetail()
        {
            var detailInfo = base.AddLogDetail();
            detailInfo.Begin(this);

            return detailInfo;
        }

        #endregion


        #region Private Helpers
        internal override void TraceBeginEvent(string messageDataName, string messageData)
        {
            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Information, ProcessDiagnosticsEventId.StepInfoStart,
                                    string.Format("Begin StepInfo Event.  StepInfoName: [{0}]", this.Name));

            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Verbose, ProcessDiagnosticsEventId.StepInfoStart,
                            string.Format("Begin StepInfo Event.  StepInfoName: [{0}], " +
                                                "StepInputName: [{1}], StepInputData[{2}]",
                                                this.Name, messageDataName, messageData));
        }


        internal override void TraceEndEvent(bool successful, string messageDataName, string messageData)
        {
            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Information, ProcessDiagnosticsEventId.StepInfoEnd,
                                    string.Format("End StepInfo Event.  StepInfoName: [{0}], Success: [{1}]",
                                    this.Name, successful));

            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Verbose, ProcessDiagnosticsEventId.StepInfoEnd,
                            string.Format("End StepInfo Event.  StepInfoName: [{0}], Success: [{1}], " +
                                                "StepOutputName: [{2}], StepOutputData: [{3}]",
                                                this.Name, successful, messageDataName, messageData));
        }


        internal override void TraceUpdateActivity(string itemName, object itemValue)
        {
            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Information, ProcessDiagnosticsEventId.ActivityUpdated,
                                    string.Format("StepInfo Update Activity.  StepInfo.{0} Value: [{1}]", itemName, itemValue));
        }

        #endregion
    }
}
